/*
 * Thread Pool Demo
 * Spring 2013 TCSS 558
 * Daniel M. Zimmerman
 */

package threadpools;

import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Locale;

/**
 * Computes a^b by repeated multiplication, printing a line 
 * when complete. (yes, this is a silly use of a thread)
 * 
 * @author Daniel M. Zimmerman
 * @version Spring 2013
 */
public class Exponentiator implements Runnable
{ 
  /**
   * The date formatter to be used.
   */
  private static final SimpleDateFormat DATE = 
    new SimpleDateFormat("yyyy-MM-dd' 'HH:mm:ss.SSS", Locale.US);
  
  /**
   * The thread sleep delay.
   */
  private static final int DELAY = 10;
  
  // Instance Fields
  
  /** 
   * The x corresponding to this exponentiator.
   */
  private final int my_x;

  /**
   * The y corresponding to this exponentiator.
   */
  private final int my_y;

  /**
   * The result generated by this exponentiator.
   */
  private BigInteger my_result = BigInteger.valueOf(1);
  
  /**
   * A boolean indicating whether the result is completely
   * generated.
   */
  private boolean my_complete;
  
  
  // Constructor
  
  /**
   * Constructs an exponentiator to compute x^y.
   * 
   * @param the_x The x.
   * @param the_y The y.
   * @exception IllegalArgumentException if the_y is negative.
   */
  public Exponentiator(final int the_x, final int the_y)
    throws IllegalArgumentException
  { 
    my_x = the_x;
    my_y = the_y;
  }

  // Instance Methods
  
  /**
   * Computes the exponent by repeated multiplication,
   * and sleeps after each iteration to allow thread interleaving. 
   */
  public void run()
  {
    synchronized (DATE) 
    {
      System.out.println(DATE.format(System.currentTimeMillis()) + 
                         ' ' + Thread.currentThread() + 
                         " Starting To Compute " + my_x + '^' + my_y);
    }
    
    int iteration = 0;
    final BigInteger big_x = BigInteger.valueOf(my_x);
    
    while (iteration < my_y)
    {
      synchronized (this)
      {
        // we lock this because my_result is long, and would
        // not otherwise be written atomically
        
        my_result = my_result.multiply(big_x);
      }
      
      iteration = iteration + 1;
      
      try
      {
        Thread.sleep(DELAY);
      }
      catch (final InterruptedException e)
      {
        // this should never happen
        System.err.println("unexpected interrupt in " + 
                           Thread.currentThread());
      }
    }
    
    synchronized (this)
    {
      // we log this to synchronize with calls to complete()
      
      my_complete = true;
    }
    
    synchronized (DATE)
    {
      System.out.println(DATE.format(System.currentTimeMillis()) + 
                         ' ' + Thread.currentThread() + 
                         " Final Result: " + my_x + '^' + my_y + " = " +
                         my_result);
    }
  }
  
  /**
   * @return the current result.
   */
  public synchronized BigInteger result()
  {
    return my_result;
  }
  
  /**
   * @return true if the result is completely computed,
   * false otherwise.
   */
  public synchronized boolean complete()
  {
    return my_complete;
  }
}
